# include "lienzo.h"

void 
Lienzo::anyadirFigura(Figura* f, bool redo)
{
	figuras.push_back(f);
	
	if (!redo)
	{
		Historial* h = new Historial(accionCrear);
		
		h->addFigura(f);
		
		historial.push(h);
		
		vaciarDeshacer();		
	}
};

bool
Lienzo::quitarFigura(Figura* f, bool redo)
{
	bool ret = false;
	
	Historial* h;
	
	for (list<Figura*>::iterator i = figuras.begin(); ret == false && i != figuras.end(); )
	{
		if (*i == f)
		{
			if (!redo)
			{
				h = new Historial(accionBorrar);
				
				h->addFigura(*i);
				
				historial.push(h);
				
				vaciarDeshacer();
			}
				
			ret = true;
			
			figuras.erase(i);
		}
		
		else
		{
			i++;
		}
	}
		
	return (ret);
}

//Devulve NULL si no hay ninguna figura seleccionada
Figura*
Lienzo::seleccionar(float x, float y)
{
	Figura* ret = NULL;
	
	for (list<Figura*>::iterator i = figuras.begin(); ret == NULL && i != figuras.end(); i++)
	{
		if ((*i)->seleccionar(x,y))
		{
			ret = *i;
		}
	}
	
	return (ret);
}

list<Figura*>
Lienzo::seleccionar(Punto x, Punto y)
{
	list<Figura*> ret;
	
	for (list<Figura*>::iterator i = figuras.begin(); i != figuras.end(); i++)
	{
		if ((*i)->contenida(x,y))
		{
			ret.push_back(*i);
		}
	}	
	
	return (ret);
}

string
Lienzo::Texto(int tab)
{
	string ret = "Lienzo:\n";
	
	for (list<Figura*>::iterator i = figuras.begin(); i != figuras.end(); i++)
	{
		ret += (*i)->Texto(tab + 1) + "\n";
	}		
	
	ret += "FinLienzo";
	
	return (ret);
}

list<Figura*>
Lienzo::Pintar()
{
	list<Figura*> ret;
	
	list<Figura*> aux;
	
	for (list<Figura*>::iterator i = figuras.begin(); i != figuras.end(); i++)
	{
		aux = (*i)->pintar();
		
		ret.splice(ret.end(), aux);
	}	
	
	return (ret);
}

Grupo*
Lienzo::agrupar (list<Figura*> l, bool redo)
{
	Grupo* grupo = new Grupo;
	
	Historial* h;
	
	for (list<Figura*>::iterator i = l.begin(); i != l.end(); i++)
	{
		grupo->anyadirElemento(*i);
	}
	
	for (list<Figura*>::iterator i = grupo->getElementos().begin(); i != grupo->getElementos().end(); i++)
	{
		quitarFigura(*i);
	}
	
	figuras.push_back(grupo);
	
	if (!redo)
	{
		h = new Historial(accionAgrupar);
		
		h->addFigura(grupo);
		
		historial.push(h);
		
		vaciarDeshacer();
	}	
	
	return (grupo);
}

void 
Lienzo::desagrupar (Grupo* g, bool redo)
{
	Historial* h = new Historial(accionDesagrupar);
	
	for (list<Figura*>::iterator i = g->getElementos().begin(); i != g->getElementos().end(); i++)
	{
		this->anyadirFigura(*i);
		
		h->addFigura(*i);
	}
	
	if (!redo)
	{
		historial.push(h);
		
		vaciarDeshacer();
	}
	
	else
	{
		delete h;
	}
	
	g->limpiarGrupo();
}

void
Lienzo::redimensionar (list<Figura*> l, float x, float y, bool redo)
{
	if (! redo)
	{
		Historial* h = new Historial(accionRedimensionar);
		
		h->setFiguras(l);
		
		h->setX(x);
		
		h->setY(y);
		
		historial.push(h);
	}
	
	for (list<Figura*>::iterator i = l.begin(); i != l.end(); i++)
	{
		if (dynamic_cast <Rectangulo*> (*i))
		{
			((Rectangulo*)*i)->redimensionar2(x,y);
		}
		
		else
		{
			(*i)->redimensionar(x, y);
		}
	}
}

void
Lienzo::trasladar (list<Figura*> l, float x, float y, bool redo)
{
	if (! redo)
	{
		Historial* h = new Historial(accionMover);
		
		h->setFiguras(l);
		
		h->setX(x);
		
		h->setY(y);
		
		historial.push(h);
	}	
	
	for (list<Figura*>::iterator i = l.begin(); i != l.end(); i++)
	{
		(*i)->trasladar(x,y);
	}
}

void
Lienzo::Iniciar()
{
	for (list<Figura*>::iterator i = figuras.begin(); i != figuras.end(); i++)
	{
		delete(*i);
	}
	
	figuras.clear();
	
	vaciarDeshacer();
	
	vaciarHistorial();
}

void
Lienzo::leerFichero(string Fichero)
{
	ifstream in;
	
	stack<Grupo*> grupos;
	
	string l = "", aux = "";
	
	Figura* f;
	
	int i = 0, j = 0, pX = 0, pY = 0, p2X = 0, p2Y = 0;
	
	in.open(Fichero.c_str(), ios::in);
	
	if (in.is_open())
	{
		getline(in, l);
		
		while (!in.eof())
		{
			aux = "";
			
			i = 0;
			
			while (l[i] == '\t') 
			{
				i++;
			}
			
			while (i < (int)l.length())
			{
				aux += l[i];
				
				i++;
			}
			
			l = aux;
			
			f = NULL;
			
			if (l == "Línea:")
			{
				i = 0;
				
				j = 0;
				
				pX = 0;
				
				pY = 0;
				
				p2X = 0;
				
				p2Y = 0;
				
				getline(in, l);
				
				while (l[i] < '0' || l[i] > '9') 
				{
					i++;
				}
				
				while (l[i] >= '0' && l[i] <= '9')
				{
					pX = pX * 10 + l[i] - '0';
					
					i++;
				}
				
				while (l[i] < '0' || l[i] > '9')
				{ 
					i++;
				}
			
				while (l[i] >= '0' && l[i] <= '9')
				{
					pY = pY * 10 + l[i] - '0';
					
					i++;
				}
				
				getline(in, l);
				
				i = 0;
				
				while (l[i] < '0' || l[i] > '9') 
				{
					i++;
				}
				
				while (l[i] >= '0' && l[i] <= '9')
				{
					p2X = p2X * 10 + l[i] - '0';
					
					i++;
				}
				
				while (l[i] < '0' || l[i] > '9') 
				{
					i++;
				}
				
				while (l[i] >= '0' && l[i] <= '9')
				{
					p2Y = p2Y * 10 + l[i] - '0';
					
					i++;
				}				
				
				f = new Linea(Punto(pX, pY), Punto(p2X, p2Y));
			}
			
			else if (l == "Rectángulo:")
			{
				i = 0;
				
				j = 0;
				
				pX = 0;
				
				pY = 0;
				
				p2X = 0;
				
				p2Y = 0;
				
				getline(in, l);
				
				while (l[i] < '0' || l[i] > '9') 
				{
					i++;
				}
				
				while (l[i] >= '0' && l[i] <= '9')
				{
					pX = pX * 10 + l[i] - '0';
					
					i++;
				}
				
				while (l[i] < '0' || l[i] > '9')
				{ 
					i++;
				}
				
				while (l[i] >= '0' && l[i] <= '9')
				{
					pY = pY * 10 + l[i] - '0';
					
					i++;
				}
				
				getline(in, l);
				
				i = 0;
				
				while (l[i] < '0' || l[i] > '9')
				{ 
					i++;
				}
				
				while (l[i] >= '0' && l[i] <= '9')
				{
					p2X = p2X * 10 + l[i] - '0';
					
					i++;
				}
				
				while (l[i] < '0' || l[i] > '9')
				{ 
					i++;
				}
				
				while (l[i] >= '0' && l[i] <= '9')
				{
					p2Y = p2Y * 10 + l[i] - '0';
					
					i++;
				}				
				
				f = new Rectangulo(Punto(pX, pY), Punto(p2X, p2Y));					
			}
			
			else if (l == "Círculo:")
			{
				i = 0;
				
				j = 0;
				
				pX = 0;
				
				pY = 0;
				
				p2X = 0;
				
				p2Y = 0;
				
				getline(in, l);
				
				while (l[i] < '0' || l[i] > '9')
				{ 
					i++;
				}
				
				while (l[i] >= '0' && l[i] <= '9')
				{
					pX = pX * 10 + l[i] - '0';
					
					i++;
				}
				
				getline(in, l);
				
				i = 0;
				
				while (l[i] < '0' || l[i] > '9') 
				{
					i++;
				}
				
				while (l[i] >= '0' && l[i] <= '9')
				{
					p2X = p2X * 10 + l[i] - '0';
					
					i++;
				}
				
				while (l[i] < '0' || l[i] > '9') 
				{
					i++;
				}
				
				while (l[i] >= '0' && l[i] <= '9')
				{
					p2Y = p2Y * 10 + l[i] - '0';
					
					i++;
				}				
				
				f = new Circulo(Punto(p2X, p2Y), pX);					
			}
			
			else if (l == "Polígono:")
			{
				f = new Poligono();
				
				i = 0;
				
				j = 0;
				
				pX = 0;
				
				pY = 0;
				
				p2X = 0;
				
				p2Y = 0;

				getline(in, l);
				
				while (l != "")
				{
					i = 0;
					
					pX = 0;
					
					pY = 0;
					
					while (l[i] < '0' || l[i] > '9') 
					{
						i++;
					}
					
					while (l[i] >= '0' && l[i] <= '9')
					{
						pX = pX * 10 + l[i] - '0';
						
						i++;
					}
					
					while (l[i] < '0' || l[i] > '9') 
					{
						i++;
					}
					
					while (l[i] >= '0' && l[i] <= '9')
					{
						pY = pY * 10 + l[i] - '0';
						
						i++;
					}
					
					((Poligono*)f) -> addPunto(Punto(pX, pY));
					
					getline(in, l);
				}
			}
			
			else if (l == "Punto:")
			{
				i = 0;
				
				j = 0;
				
				pX = 0;
				
				pY = 0;
				
				p2X = 0;
				
				p2Y = 0;
				
				getline(in, l);
				
				while (l[i] < '0' || l[i] > '9')
				{ 
					i++;
				}
				
				while (l[i] >= '0' && l[i] <= '9')
				{
					pX = pX * 10 + l[i] - '0';
					
					i++;
				}
				
				while (l[i] < '0' || l[i] > '9')
				{ 
					i++;
				}
				
				while (l[i] >= '0' && l[i] <= '9')
				{
					pY = pY * 10 + l[i] - '0';
					
					i++;
				}

				f = new PuntoDibujo(Punto(pX, pY));
			}
			
			else if (l == "Grupo:")
			{
				grupos.push(new Grupo());
			}
			
			else if (l == "FinGrupo")
			{
				if (grupos.size() > 1)
				{
					f = grupos.top();
					
					grupos.pop();
					
					grupos.top() -> anyadirElemento(f);
					
					f = NULL;
				}
				
				else if (grupos.size() == 1)
				{
					anyadirFigura(grupos.top());
					
					grupos.pop();
				}
			}
			
			else if (l != "" && l != "Lienzo:")
			{
				cout << "ERROR " << l << endl;
			}
			
			if (f != NULL)
			{
				if (grupos.empty())
				{
					anyadirFigura(f);
				}
				
				else
				{
					grupos.top() -> anyadirElemento(f);
				}
			}
			
			getline(in, l);
		}
	}
}

void
Lienzo::Deshacer()
{
	Historial* h;
	
	list<Figura*> fs;
	
	list<Figura*>::iterator i;
	
	if (!historial.empty())
	{
		h = historial.top();
		
		historial.pop();
		
		deshacer.push(h);
		
		fs = h->getFiguras();
		
		if (h -> getHist() == accionCrear)
		{
			for (i = fs.begin(); i != fs.end(); i++)
			{
				quitarFigura(*i, true);
			}
		}
		
		else if (h -> getHist() == accionBorrar)
		{
			for (i = fs.begin(); i != fs.end(); i++)
			{
				anyadirFigura(*i, true);
			}			
		}
		
		else if (h -> getHist() == accionAgrupar)
		{
			for (i = fs.begin(); i != fs.end(); i++)
			{
				if (dynamic_cast<Grupo*> (*i) != NULL)
				{
					desagrupar((Grupo*)*i, true);
				}
			}
		}
		
		else if (h -> getHist() == accionDesagrupar)
		{
			h -> setFigura(agrupar(fs, true));
		}
		
		else if (h -> getHist() == accionRedimensionar)
		{
			redimensionar(fs, -h->getX(), -h->getY(), true);
		}
		
		else if (h->getHist() == accionMover)
		{
			trasladar(fs, -h->getX(), -h->getY(), true);
		}
	}
}

void
Lienzo::Rehacer()
{
	Historial* h;
	
	list<Figura*> fs;
	
	list<Figura*>::iterator i;
	
	if (!deshacer.empty())
	{
		h = deshacer.top();
		
		deshacer.pop();
		
		historial.push(h);
		
		fs = h->getFiguras();
		
		if (h->getHist() == accionCrear)
		{
			for (i = fs.begin(); i != fs.end(); i++)
			{
				anyadirFigura(*i, true);
			}
		}
		
		else if (h->getHist() == accionBorrar)
		{
			for (i = fs.begin(); i != fs.end(); i++)
			{
				quitarFigura(*i, true);
			}			
		}
		
		else if (h->getHist() == accionAgrupar)
		{
			for (i = fs.begin(); i != fs.end(); i++)
			{
				if (dynamic_cast<Grupo*> (*i) != NULL)
				{
					agrupar(((Grupo*)*i)->getElementos(), true);
				}
			}
		}
		
		else if (h->getHist() == accionDesagrupar)
		{
			h->setFiguras(((Grupo*)fs.front())->getElementos());
			
			desagrupar((Grupo*)fs.front());
		}
		
		else if (h->getHist() == accionRedimensionar)
		{
			redimensionar(fs, h->getX(), h->getY(), true);
		}
		
		else if (h->getHist() == accionMover)
		{
			trasladar(fs, h->getX(), h->getY(), true);
		}
	}	
}
